#define _DLL_PUBLIC

#include "core.h"

#ifdef WIN32
int gettimeofday(struct timeval *tp, void *tzp)
{
	time_t clock;
	struct tm tm;
	SYSTEMTIME wtm;

	GetLocalTime(&wtm);
	tm.tm_year     = wtm.wYear - 1900;
	tm.tm_mon     = wtm.wMonth - 1;
	tm.tm_mday     = wtm.wDay;
	tm.tm_hour     = wtm.wHour;
	tm.tm_min     = wtm.wMinute;
	tm.tm_sec     = wtm.wSecond;
	tm. tm_isdst    = -1;
	clock = mktime(&tm);
	tp->tv_sec = clock;
	tp->tv_usec = wtm.wMilliseconds * 1000;

	return (0);
}
#endif

stBuffer g_buf_tmp;

static char error_buffer[1024];
int writer(void *data, uint32_t size, uint32_t nmemb, stBuffer *write_data)
{
    if (write_data == NULL)
	{
		printf("write_data is NULL");
        return 0;
    }

    uint32_t sizes = size * nmemb;

    if (MAX_DATA_SIZE - write_data->len < sizes)
	{
        printf("writer: write_data->data < sizes, sizes=%u", sizes);
        return 0;
    }

    memcpy(write_data->data + write_data->len, data, sizes);
    write_data->len += sizes;
    
    return sizes;
}

bool curl_init(CURL **pconn, const char *url, stBuffer *p_buffer, const char *field, char *method)
{
    CURLcode code;
    CURL *conn = curl_easy_init();
    if(conn == NULL)
	{
        printf("failed to create CURL connection.\n");
        return false;
    }

    *pconn = conn;
    code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
    if(code != CURLE_OK)
	{
        printf("failed to set error buffer [%d]\n", code);
        return false;
    }

    code = curl_easy_setopt(conn, CURLOPT_TIMEOUT, 10);
    if(code != CURLE_OK)
	{
        printf("failed to set url [%s]\n", error_buffer);
        return false;
    }

    code = curl_easy_setopt(conn, CURLOPT_CONNECTTIMEOUT, 10);
    if(code != CURLE_OK)
	{
        printf("failed to set url [%s]\n", error_buffer);
        return false;
    }
    
    code = curl_easy_setopt(conn, CURLOPT_URL, url);
    if(code != CURLE_OK)
	{
        printf("failed to set url [%s]\n", error_buffer);
        return false;
    }

    code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
    if(code != CURLE_OK)
	{
        printf("failed to redirect option [%s]\n", error_buffer);
        return false;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
    if(code != CURLE_OK)
	{
        printf("failed to set write data [%s]\n", error_buffer);
        return false;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
    if(code != CURLE_OK)
	{
        printf("failed to set writer [%s]\n", error_buffer);
        return false;
    }

	if (memcmp(method, "POST", 4) == 0)
	{
		code = curl_easy_setopt(conn, CURLOPT_POSTFIELDS, field);
		if(code != CURLE_OK)
		{
			printf("failed to set postfields [%s]\n", error_buffer);
			return false;
		}
	}

    return true;
}

bool send_curl(const char *url, const char *field, char *method)
{
    CURL* conn = NULL;
    CURLcode code;

    memset(&g_buf_tmp, 0, sizeof(g_buf_tmp));
    
    g_buf_tmp.len = 0;
    if (curl_init(&conn, url, &g_buf_tmp, field, method) == false)
	{
        printf("send_curl: connection initialize failed\n");
        curl_easy_cleanup(conn);
        return false;
    }

    code = curl_easy_perform(conn);
    if(code != CURLE_OK)
	{
        printf("send_curl: failed to get %s(%s)\n", url, error_buffer);
        curl_easy_cleanup(conn);
        return false;
    }

    long status = 0;
    code = curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &status);
    if (code != CURLE_OK || status != 200)
	{
        printf("send_curl: The Response status is: %ld\n", status);
        curl_easy_cleanup(conn);
        return false;
    }
    curl_easy_cleanup(conn);
    return true; 
}

void add_base_parameter(std::map<std::string, std::string> &mapCommonParameter, std::vector<std::string> &vecCommonParameter)
{
	time_t curtime = time(0); 
	tm *gmTime = NULL;
	gmTime = gmtime(&curtime);

	char signatureNonce[128] = {0};
	struct timeval tv;    
	gettimeofday(&tv,NULL);    
	uint32_t mstimestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; 
	sprintf(signatureNonce, "%d", mstimestamp);
	char timestamp[128] = {0};
	sprintf(timestamp, "%d-%02d-%02dT%02d:%02d:%02dZ", gmTime->tm_year+1900, gmTime->tm_mon+1,
		gmTime->tm_mday, gmTime->tm_hour, gmTime->tm_min, gmTime->tm_sec);
	mapCommonParameter.insert(std::make_pair("Timestamp", timestamp));
	mapCommonParameter.insert(std::make_pair("SignatureNonce", signatureNonce));
	mapCommonParameter.insert(std::make_pair("SignatureMethod", "HMAC-SHA1"));
	mapCommonParameter.insert(std::make_pair("SignatureVersion", "1.0"));
	vecCommonParameter.push_back("Timestamp");
	vecCommonParameter.push_back("SignatureNonce");
	vecCommonParameter.push_back("SignatureMethod");
	vecCommonParameter.push_back("SignatureVersion");
}

void parseMetaResponse(Json::Value &result, struct SResponseMap &responseMap)
{	
	int size = result["members"].size();
	for (int i=0; i<size; i++)
	{
		SMember member;
		member.tagName = result["members"][i]["tagName"].asString();
		member.type = result["members"][i]["type"].asString();
		responseMap.members.push_back(member);
	}

	size = result["structs"].size();
	for (int i=0; i<size; i++)
	{
		struct SResponseMap *pStructNode = new SResponseMap;
		pStructNode->tagName = result["structs"][i]["tagName"].asString();
		pStructNode->itemName = result["structs"][i]["itemName"].asString();
		responseMap.vStructNode.push_back(pStructNode);
		if (!result["structs"][i]["members"].isNull())
		{
			parseMetaResponse(result["structs"][i], *pStructNode);
			return;
		}
	}

	size = result["arrays"].size();
	for (int i=0; i<size; i++)
	{
		struct SResponseMap *pArraysNode = new SResponseMap;
		pArraysNode->tagName = result["arrays"][i]["tagName"].asString();
		pArraysNode->itemName = result["arrays"][i]["itemName"].asString();
		responseMap.vArraysNode.push_back(pArraysNode);
		if (!result["arrays"][i]["members"].isNull())
		{
			parseMetaResponse(result["arrays"][i], *pArraysNode);
			return;
		}
	}
}